<template>
  <a-menu v-model:selectedKeys="current" :items="menus" mode="horizontal" theme="dark" @select="handleSelectMenu"/>
  <div class="dnd-flow" @drop="onDrop">
    <VueFlow
        @pane-ready="onPaneReadyEvent"
        v-model:edges="edges"
        v-model:nodes="nodes"
        class="custom-node-flow"
        fit-view-on-init
        @connect="onConnect"
        @dragleave="onDragLeave"
        @dragover="onDragOver"
        @nodeClick="handleNodeClick"
        @node-context-menu="handleNodeContextMenu($event,true)"
    >
      <SaveRestoreControls :knowledgeConclusions="knowledgeConclusions" :nodes="nodes" :queId="route.query.id"
                           @addMutil="handleNodeContextMenu(false)" @update-nodes="handleUpdateNodes"/>
      <Background/>
      <template #node-special="props">
        <customNode :processingTypeList="processingTypeList" :data="props.data" :id="props.id" :type="1"/>
      </template>
      <template #edge-custom="customEdgeProps">
        <CustomEdge
            :id="customEdgeProps.id"
            :source-x="customEdgeProps.sourceX"
            :source-y="customEdgeProps.sourceY"
            :target-x="customEdgeProps.targetX"
            :target-y="customEdgeProps.targetY"
            :source-position="customEdgeProps.sourcePosition"
            :target-position="customEdgeProps.targetPosition"
            :data="customEdgeProps.data"
            :marker-end="customEdgeProps.markerEnd"
            :style="customEdgeProps.style"
        />
      </template>
      <MiniMap :node-color="nodeColor" :node-stroke-color="nodeStroke"/>
    </VueFlow>
    <Sidebar :processingTypeList="processingTypeList" :nodeTypeLogo="nodeTypeLogo"/>
    <a-drawer
        v-model:open="open1"
        :closable="false"
        :footer-style="{ textAlign: 'right' }"
        :width="980"
        placement="right"
        @close="onClose1"
        v-if="open1"
        :maskClosable="false"
    >
      <template #footer>
        <a-button type="primary"  style="margin-right: 8px" @click="onOk1" >保存</a-button>
        <a-button @click="onClose1">取消</a-button>
      </template>
      <div class="drawer-card">
        <h3 class="drawer-card-title">
          批量新增
        </h3>
        <a-select
            ref="select"
            style="width: 100%"
            v-model:value="formData.type"
            class="type"
            @change="handleChange"
        >
          <a-select-option v-for="(processingType,index) in processingTypeList " :value="processingType.value" :key="index">
            <div  class="custom_node">
              <i :style="{backgroundImage:`url(${encodeURI(processingType.icon)})`}" class="custom_node-logo" />
              <span class="custom_node_label">
                  {{processingType.label}}
                </span>
            </div>
          </a-select-option>
        </a-select>
      </div>
      <div class="drawer-card">
        <h3 class="drawer-card-title">
          带分割内容
        </h3>
        <vditorEditor
            :height="600"
            ref="queDrawer"
            v-model="formData.content"
            class="queDrawer"/>
      </div>
    </a-drawer>
  </div>

</template>
<script setup>

import {h, ref} from 'vue';
import {AppstoreOutlined} from '@ant-design/icons-vue';
import {useRoute, useRouter} from 'vue-router'
import {MiniMap} from '@vue-flow/minimap'
import {useVueFlow, VueFlow} from '@vue-flow/core'
import customNode from './customNode.vue'
import Sidebar from "./Sidebar.vue";
import useDragAndDrop from "./useDnD";
import {Background} from "@vue-flow/background";
import {
  editProcessData,
  getKnowledgeDetail,
  queryPageEdgeData,
  queryPageKnowledgeConclusionByIds,
  queryPageNodeData,
  queryPageNodeType
} from "@/renderer/api/dict";
import {message} from 'ant-design-vue';
import SaveRestoreControls from './controlPanel.vue'
import {presets} from "@/renderer/views/vue-flow/presets";
import CustomEdge from "@/renderer/views/vue-flow/CustomEdge.vue";
import VditorEditor from "@/renderer/views/vue-flow/vditorEditor.vue";

const current = ref(['']);
let menu = ref([]);


const {onDragOver, onDrop, onDragLeave, isDragOver, addNode, addMultipleNode} = useDragAndDrop()
const {addEdges,toObject,getViewport, fitView} = useVueFlow()
const router = useRouter()
const route = useRoute()
let nodes = ref([])
let edges = ref([])
const processingTypeList = ref([])
const nodeTypeLogo = reactive({})
const nodeMap = reactive({})
let instance =ref(null)
const open1 = ref(false);
const { onPaneReady } = useVueFlow()
let nodeFlag = ref(false)


let formData =reactive({
  content: '',
  type: '',
})
let  knowledgeConclusions =ref([])
let  nodeSelect = ref(null)


document.addEventListener('keydown', function(event) {
  if (event.ctrlKey) {
    switch (event.key.toLowerCase()) {
      case 's':
        event.preventDefault();
        saveContent();
        break;
    }
  }
});

onMounted(()=>{
  document.querySelector('.dnd-flow').addEventListener('keydown', function(event) {
    if (event.ctrlKey) {
      switch (event.key.toLowerCase()) {
        case 'c':
          event.preventDefault();
          logCopyAttempt();
          break;
      }
    }
  });
})


function saveContent() {
  const hide = message.loading('保 存 中..', 0);
  let {nodes, edges} = toObject();
  let nodeDataList = nodes.map(item => {
    return {...item.position, id: item.id, queId: route.query.id, nodeName: item.data.nodeName,nodeType:item.data.type,                 nodeContent: item.data.nodeContent,
      nodeTitle:item.data.nodeTitle,nodeDataSubList:item.data.nodeDataSubList}
  })
  let edgeDataList = edges.map(item => {
    return {
      ...item, queId: route.query.id, name: item.data.name,
      sourceNodeId: item.source,
      targetNodeId: item.target
    }
  })
  const data = {nodeDataList, edgeDataList, queId: route.query.id}
  editProcessData(data).then(res => {
  }).finally(()=>{
    hide()
  })

}


function logCopyAttempt() {
  message.info('用户尝试复制內容。');
  addNode(nodeSelect.value, true)
}

let onPaneReadyEvent = (vueFlowInstance) =>{
  vueFlowInstance.fitView()
  instance.value = vueFlowInstance
}


let navigatorList = computed(() => {
  return nodes.value.filter(item => {
    return item.data.type==='module'
  })
})


let menus = computed(() => {
  return navigatorList.value.map(item => {
    return {
      key:item.id,
      icon: () => h(AppstoreOutlined),
      label: item.data.nodeTitle,
      title: item.data.nodeTitle,
    }
  })
})



let  handleSelectMenu =  (item)=>{
  let find = navigatorList.value.find(sub=>sub.id===item.key);
  localStorage.setItem(`knowId:${route.query.id}`, find.id);
  instance.value.fitView({
    nodes: [find.id],
    duration: 800,
    minZoom: 0.5,
    maxZoom: 0.9,
    offset: {
      x: -360, // A negative x value shifts the content to the left
      y: 0     // No vertical shift
    }
  });
}

const getNodeTypeList = async () => {
  getKnowledgeDetail({id:route.query.id}).then(res=>{
    document.title = res.data.title
  })
  try {
    queryPageKnowledgeConclusionByIds({ ids: [route.query.id], type: '03'}).then(res=>{
      knowledgeConclusions.value.push(...res.data)
    })
    const res = await queryPageNodeType({}, {})
    if (res.code === 200) {
      processingTypeList.value.length = 0 // Clear array while keeping reactivity
      processingTypeList.value.push(...res.rows)
      res.rows.forEach(item => {
        nodeTypeLogo[item.value] = item
      })
      await fetchGraphElements()


      let nodeId = localStorage.getItem(`knowId:${route.query.id}`);
      if (nodeId) {
        instance.value.fitView({
          nodes: [nodeId],
          duration: 800,
          minZoom: 0.5,
          maxZoom: 0.9,
          offset: {
            x: -360, // A negative x value shifts the content to the left
            y: 0     // No vertical shift
          }
        })
        current.value = [nodeId]
      } else {
        instance.value.fitView()
      }


    } else {
      message.error(res.message || 'Failed to load node types')
    }
  } catch (error) {
    message.error('Error fetching node types: ' + error.message)
  }
}

let  handleNodeClick = ({event, edge,node})=>{
  nodeSelect.value = node
}
let handleNodeContextMenu = (e, flag) => {

  nodeFlag.value = flag
  let draggedType = null;
  if (nodeFlag.value) {
    let {event,node} = e;
    event.preventDefault()
    nodeSelect.value = node
    draggedType = nodeTypeLogo['detail_item'];
  } else {
    draggedType = nodeTypeLogo['module'];
  }

  copyNode(draggedType);
  open1.value = true
}



let copyNode = (draggedType) => {
  formData = {
    ...formData,
    type: draggedType.value,
    icon: draggedType.icon,
    api: draggedType.api,
    submitApi: draggedType.submitApi,
    outFlag:draggedType.outFlag,
    inFlag:draggedType.inFlag,
    upFlag:draggedType.upFlag,
    downFlag:draggedType.downFlag,
    maxWidth:draggedType.maxWidth,
    config:draggedType.customConfig
  }
}


const handleChange = (e,option) => {
  let draggedType = processingTypeList.value[option.key];
  copyNode(draggedType);
};

const onClose1 = (e) => {
  open1.value = false;
};
const onOk1 = (e) => {
  let draggedType = nodeTypeLogo[formData.type];
  if (nodeFlag.value) {
    let filter = formData.content.split('\n').filter(item=>item.trim()!=='');
    let position = {
      y: nodeSelect.value.position.y  -  Math.ceil(filter.length * 50)+50,
      x: nodeSelect.value.position.x +nodeSelect.value.dimensions.width + 100
    }
    addMultipleNode(formData, position, draggedType,true,nodeSelect.value)
  } else {
    const {x, y, zoom} = getViewport()
    addMultipleNode(formData, {x, y}, draggedType,false)
  }


  open1.value = false;
};
const fetchGraphElements = async () => {
  if (!route.query.id) {
    nodes.value = []
    edges.value = []
  }
  try {
    const nodeRes = await queryPageNodeData({queId: route.query.id})
    if (nodeRes.code === 200) {
       nodes.value.push(
           ... nodeRes.rows.map(item => {
             nodeMap[item.id] = item
             const typeData = nodeTypeLogo[item.nodeType]
             return {
               id: item.id,
               type: 'special',
               position:{
                 x: Number(item.x),
                 y: Number(item.y),
               },
               data: {
                 nodeName: item.nodeName,
                 nodeContent: !!item.nodeContent?item.nodeContent:'',
                 nodeTitle: !!item.nodeTitle?item.nodeTitle:'',
                 type: item.nodeType,
                 customWidth: item.customWidth,
                 maxWidth:typeData.maxWidth,
                 icon: typeData.icon,
                 api: typeData.api,
                 submitApi: typeData.submitApi,
                 outFlag:typeData.outFlag,
                 inFlag:typeData.inFlag,
                 upFlag:typeData.upFlag,
                 downFlag:typeData.downFlag,
                 config:typeData.customConfig,
                 complex:typeData.complex,
                 nodeTypeList:typeData.nodeTypeList,
                 nodeDataSubList:item.nodeDataSubList,
                 knowledgeConclusionTag:item.knowledgeConclusionTagId,
                 conclusionId:item.conclusionId,
                 nodeBindConclusionId:item.nodeBindConclusionId,
                 knowledgeConclusionId:item.knowledgeConclusionId,
                 knowledgeConclusionLabel:item.knowledgeConclusionLabel
               }
             }
           })
       )

      const edgeRes = await queryPageEdgeData({queId: route.query.id})
      if (edgeRes.code === 200) {
        const filteredEdges = edgeRes.rows.filter(item => nodeMap[item.sourceNodeId] && nodeMap[item.targetNodeId])
         edges.value.push(
             ...filteredEdges.map(item => {
               return {
                 id: item.id,
                 "type": "default",
                 "source": item.sourceNodeId,
                 "target": item.targetNodeId,
                 "sourceHandle": item.sourceHandle,
                 "targetHandle": item.targetHandle,
                 "data": {},
                 "label": "",
                 "sourceX": item.sourceX,
                 "sourceY": item.sourceY,
                 "targetX": item.targetX,
                 "targetY": item.targetY,

               }
             })
         )
      }
    } else {
     message.error(nodeRes.message || 'Failed to load node data')
    }
  } catch (error) {
    message.error('Error fetching graph elements: ' + error.message)
  }
}

onMounted(() => {
  getNodeTypeList();
})

// minimap stroke color functions
function nodeStroke(n) {
  switch (n.type) {
    case 'input':
      return '#0041d0'
    case 'color-selector':
      return n.data.color
    case 'output':
      return '#ff0072'
    default:
      return '#eee'
  }
}

function nodeColor(n) {
  if (n.type === 'color-selector') {
    return n.data.color
  }

  return '#333'
}




function onConnect(params) {

  params.id= new Date().getTime()
  addEdges(params)
}



let  handleUpdateNodes = (data)=>{
  let  dataMap = {};
  nodes.value.forEach(item=>{
    dataMap[item.id] =  item
  })

  let conclusionMap = {};
  knowledgeConclusions.value.forEach(item=>{
    conclusionMap[item.id] =  item
  })
  data.forEach(item=>{
    let dataMapElement = dataMap[item.knowNodeId];
    let conclusionMapElement = conclusionMap[item.knowledgeConclusionId];
    dataMapElement.data.knowledgeConclusionTag =   item.knowledgeConclusionTag;
    dataMapElement.data.conclusionId =   item.id;
    dataMapElement.data.nodeBindConclusionId =   item.nodeBindConclusionId;
    dataMapElement.data.knowledgeConclusionId =   item.knowledgeConclusionId;
    dataMapElement.data.knowledgeConclusionLabel =   conclusionMapElement.title;



  })

}
</script>

<style lang="less" scoped>
@import "style.less";

.custom-node-flow{
  background-color:#edf2f7;
}

.queDrawer {
  border: 1px solid #e8e8e8 !important;
}
.drawer-card-title {
  font-weight: 700;
  padding: 15px 0;
}
.custom_node {
  font-weight:500;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  width: 100%;
  height: 100%;
  color: rgba(0, 0, 0, 65%);
  font-size: 12px;
  font-family: PingFangSC;
  &-logo {
    display: inline-block;
    width: 24px;
    height: 24px;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 100%;
  }
  &-label {
    color: #000;
  }
}
.navigator{
  position: fixed;
  right: 20px;
  top: 0;
}

/deep/ .vue-flow__node.selected {
  box-shadow: 0 0 0 2px #2563eb !important;
}



</style>
